package com.hyt.it.ogt.kq.service.gov.service.impl;

import com.alibaba.excel.EasyExcel;
import com.hyt.core.base.BaseServiceImpl;
import com.hyt.it.ogt.kq.common.gov.constant.ResponseCode;
import com.hyt.it.ogt.kq.common.gov.constant.StringCodeEnum;
import com.hyt.it.ogt.kq.common.config.exception.KqException;
import com.hyt.it.ogt.kq.service.gov.mapper.OfficeCandidateAreaMapper;
import com.hyt.it.ogt.kq.service.gov.model.entity.OfficeCandidateArea;
import com.hyt.it.ogt.kq.service.gov.model.excel.AreaSheet;
import com.hyt.it.ogt.kq.service.gov.model.excel.listener.AreaListener;
import com.hyt.it.ogt.kq.service.gov.service.IOfficeCandidateAreaService;
import com.hyt.it.ogt.kq.common.gov.utils.TextUtil;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
import java.util.stream.Collectors;

/**
 * <p>
 * 机构考生所属区域表 服务实现类
 * </p>
 *
 * @author huangyh
 * @since 2021-07-26
 */
@Service
public class OfficeCandidateAreaServiceImpl extends BaseServiceImpl<OfficeCandidateAreaMapper, OfficeCandidateArea> implements IOfficeCandidateAreaService {

    @Override
    public void initOfficeCandidateArea(String officeId) {
        Integer count = this.lambdaQuery()
                .eq(OfficeCandidateArea::getOfficeId,officeId)
                .eq(OfficeCandidateArea::getDelFlag,false)
                .count();
        if (count <= 0) {
            baseMapper.initOfficeCandidateArea(officeId);
        }
    }

    @Override
    public void removeOfficeCandidateArea() {
        this.lambdaUpdate()
                .set(OfficeCandidateArea::getDelFlag,true)
                .update();
    }

    @Override
    public void importOfficeCandidateArea(MultipartFile file, String officeId) throws KqException, IOException {
        //校验excel文件
        this.excelVerify(file);
        //校验机构是否存在机构考生区域数据
        this.checkOfficeCandidateAreaExist(officeId);
        //读取excel文件
        List<AreaSheet> areaSheetList = this.readExcel(file);
        //校验excel内容
        this.contentVerify(areaSheetList);
        //组装数据
        List<OfficeCandidateArea> officeCandidateAreaList = this.convertSysArea(areaSheetList, officeId);
        //保存机构考生区域数据
        this.saveOfficeCandidateArea(officeCandidateAreaList);
    }

    /**
     * 校验excel文件
     * @param file excel文件
     * @throws KqException 异常
     */
    private void excelVerify(MultipartFile file) throws KqException {
        if (file.isEmpty()) {
            //导入文件不存在
            throw new KqException(ResponseCode.IMPORT_FILE_NOT_EXIST.getCode(),
                    ResponseCode.IMPORT_FILE_NOT_EXIST.getMsg());
        }
        String fileName = file.getOriginalFilename();
        if (fileName == null) {
            //导入文件类型错误
            throw new KqException(ResponseCode.WRONG_FILE_TYPE.getCode(),
                    ResponseCode.WRONG_FILE_TYPE.getMsg());
        }
        String ext = FilenameUtils.getExtension(fileName);
        if (!ext.equalsIgnoreCase(StringCodeEnum.EXCEL_XLS.getCode())
                && !ext.equalsIgnoreCase(StringCodeEnum.EXCEL_XLSX.getCode())) {
            //导入文件类型错误
            throw new KqException(ResponseCode.WRONG_FILE_TYPE.getCode(),
                    ResponseCode.WRONG_FILE_TYPE.getMsg());
        }
    }

    /**
     * 校验机构是否存在机构考生区域数据
     * @param officeId 机构id
     * @throws KqException 异常
     */
    private void checkOfficeCandidateAreaExist(String officeId) throws KqException {
        Integer count = this.lambdaQuery()
                .eq(OfficeCandidateArea::getOfficeId, officeId)
                .eq(OfficeCandidateArea::getDelFlag, false)
                .count();
        if (count > 0) {
            //当前机构存在机构考生区域数据，无法导入
            throw new KqException(ResponseCode.HAS_OFFICE_CANDIDATE_AREA.getCode(),
                    ResponseCode.HAS_OFFICE_CANDIDATE_AREA.getMsg());
        }
    }

    /**
     * 读取excel文件
     * @param file excel文件
     * @return excel内容
     * @throws IOException IO异常
     */
    private List<AreaSheet> readExcel(MultipartFile file) throws IOException {
        AreaListener areaListener = new AreaListener();
        EasyExcel.read(file.getInputStream(), AreaSheet.class, areaListener)
                .sheet().doRead();
        return areaListener.getDataList();
    }

    /**
     * 校验excel内容
     * @param areaSheetList excel内容
     * @throws KqException 异常
     */
    private void contentVerify(List<AreaSheet> areaSheetList) throws KqException {
        if (CollectionUtils.isEmpty(areaSheetList)) {
            throw new KqException(ResponseCode.SYS_AREA_EXCEL_CONTENT_ERROR.getCode(), "导入的excel为空");
        }
        for (int i = 0; i < areaSheetList.size(); i++) {
            AreaSheet area = areaSheetList.get(i);
            int rowNumber = i + 1;
            if (StringUtils.isEmpty(area.getCountryName())) {
                throw new KqException(ResponseCode.SYS_AREA_EXCEL_CONTENT_ERROR.getCode(), "第" + rowNumber + "行数据国名称为空");
            }
            if (!TextUtil.isLongNum(area.getCityCode())) {
                throw new KqException(ResponseCode.SYS_AREA_EXCEL_CONTENT_ERROR.getCode(), "第" + rowNumber + "行数据国编码格式不正确");
            }
            if (StringUtils.isEmpty(area.getProvinceName())) {
                throw new KqException(ResponseCode.SYS_AREA_EXCEL_CONTENT_ERROR.getCode(), "第" + rowNumber + "行数据省名称为空");
            }
            if (!TextUtil.isLongNum(area.getProvinceCode())) {
                throw new KqException(ResponseCode.SYS_AREA_EXCEL_CONTENT_ERROR.getCode(), "第" + rowNumber + "行数据省编码格式不正确");
            }
            // 完善各字段校验
        }

    }

    /**
     * 组装区域数据
     * @param areaSheetList excel内容
     * @return 组装结果
     */
    private List<OfficeCandidateArea> convertSysArea(List<AreaSheet> areaSheetList, String officeId) {
        //筛选国数据
        List<AreaSheet> countryList = areaSheetList.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(AreaSheet::getCountryCode))), ArrayList::new
                ));
        //筛选省数据
        List<AreaSheet> provinceList = areaSheetList.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(AreaSheet::getProvinceCode))), ArrayList::new
                ));
        //筛选市数据
        List<AreaSheet> cityList = areaSheetList.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(AreaSheet::getCityCode))), ArrayList::new
                ));
        //筛选区县数据
        List<AreaSheet> districtList = areaSheetList.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(AreaSheet::getDistrictCode))), ArrayList::new
                ));
        //组装国
        List<OfficeCandidateArea> officeCandidateAreaList = countryList.stream().map(country -> {
            OfficeCandidateArea officeCandidateArea = new OfficeCandidateArea();
            officeCandidateArea.setAreaId(country.getCountryCode())
                    .setName(country.getCountryName())
                    .setType("1")
                    .setOfficeId(officeId);
            return officeCandidateArea;
        }).collect(Collectors.toList());
        //组装省
        List<OfficeCandidateArea> provinceAreaList = provinceList.stream().map(province -> {
            OfficeCandidateArea officeCandidateArea = new OfficeCandidateArea();
            officeCandidateArea.setAreaId(province.getProvinceCode())
                    .setParentId(province.getCountryCode())
                    .setParentIds(province.getCountryCode())
                    .setName(province.getProvinceName())
                    .setType("2")
                    .setOfficeId(officeId);
            return officeCandidateArea;
        }).collect(Collectors.toList());
        officeCandidateAreaList.addAll(provinceAreaList);
        //组装市
        List<OfficeCandidateArea> cityAreaList = cityList.stream().map(city -> {
            OfficeCandidateArea officeCandidateArea = new OfficeCandidateArea();
            officeCandidateArea.setAreaId(city.getCityCode())
                    .setParentId(city.getProvinceCode())
                    .setParentIds(StringUtils.join(city.getCountryCode(), ",", city.getProvinceCode()))
                    .setName(city.getCityName())
                    .setType("3")
                    .setOfficeId(officeId);
            return officeCandidateArea;
        }).collect(Collectors.toList());
        officeCandidateAreaList.addAll(cityAreaList);
        //组装区县
        List<OfficeCandidateArea> districtAreaList = districtList.stream().map(district -> {
            OfficeCandidateArea officeCandidateArea = new OfficeCandidateArea();
            officeCandidateArea.setAreaId(district.getDistrictCode())
                    .setParentId(district.getCityCode())
                    .setParentIds(StringUtils.join(district.getCountryCode(), ",", district.getProvinceCode(), ",", district.getCityCode()))
                    .setName(district.getDistrictName())
                    .setType("4")
                    .setOfficeId(officeId);
            return officeCandidateArea;
        }).collect(Collectors.toList());
        officeCandidateAreaList.addAll(districtAreaList);
        return officeCandidateAreaList;
    }

    /**
     * 保存机构考生区域数据
     * @param officeCandidateAreaList 机构考生区域数据
     * @throws KqException 异常
     */
    private void saveOfficeCandidateArea(List<OfficeCandidateArea> officeCandidateAreaList) throws KqException {
        if (!saveBatch(officeCandidateAreaList)) {
            //插入机构考生区域表失败
            throw new KqException(ResponseCode.IMPORT_SYS_AREA_EXCEPTION.getCode(),
                    ResponseCode.IMPORT_SYS_AREA_EXCEPTION.getMsg());
        }
    }


}
